/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package operators;

import genotypes.Angles;
import genotypes.AnglesComparator;
import genotypes.AnglesPopulation;
import java.util.Arrays;
import java.util.Random;

/**
 *
 * @author rusak
 */
public class RankSelection implements SelectionOperator {

    private int groupFactor;
    private int groupSize;
    private double deterministicFactor;
    private double steps[];
    private Random r = new Random();

    public RankSelection(int groupFactor, double deterministicFactor) {
        this.groupFactor = groupFactor;
        this.deterministicFactor = deterministicFactor;

    }

    private int[] randomGroup(int size, int popSize) {

        boolean chosen[] = new boolean[popSize];
        int result[] = new int[size];
        int nextInGroup;
        for (int i = 0; i < size; i++) {
            nextInGroup = r.nextInt(popSize);
            while (chosen[nextInGroup]) {
                nextInGroup = r.nextInt(popSize);
            }
            chosen[nextInGroup] = true;
            result[i] = nextInGroup;
        }
        /*    System.out.println("RANDOMLY CHOSEN: ");
        for(int i=0;i<size;i++) {
        System.out.print(result[i]+" ");
        }
        System.out.println();*/
        return result;
    }

    private Angles selectFromGroup(AnglesPopulation pop, int group[]) {

        int size = group.length;
        Angles anGroup[] = new Angles[size];
        for (int i = 0; i < size; i++) {
            anGroup[i] = pop.getAnglesAt(group[i]);
        }
        Arrays.sort(anGroup, new AnglesComparator());
        Angles chosen = anGroup[0];
        double randomValue = r.nextDouble();
        for (int i = 0; i < size; i++) {
            if (randomValue < steps[i]) {
                chosen = anGroup[i];
                break;
            }
        }
        return chosen.copy();
    }

    private double[] computeSteps(int groupSize) {
        double result[] = new double[groupSize];
        result[0] = deterministicFactor;
        for (int i = 1; i < groupSize; i++) {
            result[i] = result[i - 1] * (1 - deterministicFactor);
        }
        return result;
    }

    @Override
    public AnglesPopulation select(AnglesPopulation pop) {
        if (pop.getSize() > 1) {
            int popSize = pop.getSize();
            groupSize = popSize > groupFactor ? popSize / groupFactor : 1;
            steps = computeSteps(groupSize);
            Angles newAngles[] = new Angles[popSize];
            for (int i = 0; i < popSize; i++) {
                newAngles[i] = selectFromGroup(pop, randomGroup(groupSize, popSize));
                //   System.out.println("SELECTED: " + newAngles[i]);
            }
            return new AnglesPopulation(newAngles);
        } else {
            return pop;
        }
    }
}
